#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "ohos_init.h"       // OpenHarmony 初始化相关头文件
#include "cmsis_os2.h"       // CMSIS-RTOS2 接口

#include "wifi_connect.h"    // WiFi 连接功能
#include "lwip/sockets.h"    // LWIP 套接字

#include "oc_mqtt.h"         // 华为云 MQTT 协议接口
#include "DHT11_driver.h"    // DHT11 温湿度传感器驱动

#define MSGQUEUE_OBJECTS 16  // 消息队列对象数量

// 消息队列对象结构体
typedef struct
{
    char *Buf;    // 缓冲区指针
    uint8_t Idx;  // 索引
} MSGQUEUE_OBJ_t;

MSGQUEUE_OBJ_t msg;  // 消息队列对象实例
osMessageQueueId_t mid_MsgQueue;  // 消息队列ID

// WiFi 配置 (需根据实际修改)
#define CONFIG_WIFI_SSID          "OPPO Find X7 Ultra"  // WiFi 热点名称
#define CONFIG_WIFI_PWD           "52800000"            // WiFi 密码

// 华为云IoT平台设备认证信息
#define CLIENT_ID "685b59e432771f177b459029_bearpi_hi3861_0_0_2025062507"
#define USERNAME "685b59e432771f177b459029_bearpi_hi3861"
#define PASSWORD "a03741bf00ee2bf2aa05e8795d3f54f2dc00157c7d67a3a1ba65ca831e9ccbf8"

// 温湿度统计数据结构体
typedef struct {
    int temp_max;  // 最高温度
    int temp_min;  // 最低温度
    int temp_sum;  // 温度总和 (用于计算平均值)
    int hum_max;   // 最高湿度
    int hum_min;   // 最低湿度
    int hum_sum;   // 湿度总和 (用于计算平均值)
    int count;     // 数据点计数
} stat_data_t;

static stat_data_t g_stat_data = {0};  // 全局统计数据结构实例

/**
 * @brief 初始化统计数据结构
 */
void stat_init(void) {
    memset(&g_stat_data, 0, sizeof(g_stat_data));
    g_stat_data.temp_min = INT_MAX;  // 初始化为最大整数
    g_stat_data.hum_min = INT_MAX;
    g_stat_data.temp_max = INT_MIN;  // 初始化为最小整数
    g_stat_data.hum_max = INT_MIN;
}

/**
 * @brief 更新统计数据
 * @param temp 当前温度值
 * @param hum  当前湿度值
 */
void stat_update(int temp, int hum) {
    // 更新温度统计
    if (temp > g_stat_data.temp_max) g_stat_data.temp_max = temp;
    if (temp < g_stat_data.temp_min) g_stat_data.temp_min = temp;
    g_stat_data.temp_sum += temp;
    
    // 更新湿度统计
    if (hum > g_stat_data.hum_max) g_stat_data.hum_max = hum;
    if (hum < g_stat_data.hum_min) g_stat_data.hum_min = hum;
    g_stat_data.hum_sum += hum;
    g_stat_data.count++;  // 增加计数
}

/**
 * @brief 获取当前统计数据快照
 * @return 当前统计数据的副本
 */
stat_data_t stat_get(void) {
    return g_stat_data;  // 返回当前统计数据的副本
}

// 消息类型枚举
typedef enum
{
    en_msg_cmd = 0,        // 命令消息
    en_msg_report,          // 实时数据上报
    en_msg_stat_report      // 统计数据上报
} en_msg_type_t;

// 命令消息结构体
typedef struct
{
    char *request_id;  // 请求ID
    char *payload;     // 有效载荷 (JSON格式)
} cmd_t;

// 实时数据上报结构体
typedef struct
{
    int temp;  // 温度值
    int hum;   // 湿度值
} report_t;

// 应用消息联合体
typedef struct
{
    en_msg_type_t msg_type;  // 消息类型
    union  // 根据消息类型使用不同的数据结构
    {
        cmd_t cmd;            // 命令消息
        report_t report;      // 实时数据
        stat_data_t stat_data;// 统计数据
    } msg;
} app_msg_t;

// 应用状态控制块
typedef struct
{
    int connected;  // 连接状态
    int led;        // LED状态
    int motor;      // 电机状态
} app_cb_t;
static app_cb_t g_app_cb;  // 全局应用控制块实例

/**
 * @brief 处理实时数据上报
 * @param report 包含温湿度数据的结构体指针
 */
static void deal_report_msg(report_t *report)
{
    // 创建华为云服务数据结构
    oc_mqtt_profile_service_t service;
    oc_mqtt_profile_kv_t temperature;  // 温度键值对
    oc_mqtt_profile_kv_t humidity;     // 湿度键值对

    // 配置服务属性
    service.event_time = NULL;  // 事件时间 (无)
    service.service_id = "DHT11";  // 服务ID
    service.service_property = &temperature;  // 指向温度属性
    service.nxt = NULL;  // 无下一个服务

    // 配置温度属性
    temperature.key = "Temperature";  // 属性键名
    temperature.value = &report->temp;  // 属性值指针
    temperature.type = EN_OC_MQTT_PROFILE_VALUE_INT;  // 整数类型
    temperature.nxt = &humidity;  // 指向下一个属性(湿度)

    // 配置湿度属性
    humidity.key = "Humidity";
    humidity.value = &report->hum;
    humidity.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    humidity.nxt = NULL;  // 最后一个属性

    // 打印调试信息
    printf("湿度：%d,温度:%d", report->hum, report->temp);
    
    // 上报属性到华为云IoT平台
    oc_mqtt_profile_propertyreport(USERNAME, &service);
}

/**
 * @brief 处理统计数据上报
 * @param stat 统计数据结构指针
 */
static void deal_stat_report(stat_data_t *stat) {
    if (stat->count == 0) return;  // 无有效数据则跳过
    
    // 计算温度平均值
    char temp_avg1[20];
    snprintf(temp_avg1, sizeof(temp_avg1), "%.1f", (float)stat->temp_sum / stat->count);
    
    // 计算湿度平均值
    char hum_avg1[20];
    snprintf(hum_avg1, sizeof(hum_avg1), "%.1f", (float)stat->hum_sum / stat->count);
    
    // 创建华为云服务数据结构
    oc_mqtt_profile_service_t service;
    // 创建温度统计属性
    oc_mqtt_profile_kv_t temp_max, temp_min, temp_avg;
    // 创建湿度统计属性
    oc_mqtt_profile_kv_t hum_max, hum_min, hum_avg;
    
    // 配置温度最大属性
    temp_max.key = "TempMax";
    temp_max.value = &stat->temp_max;
    temp_max.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    temp_max.nxt = &temp_min;  // 指向下一个属性
    
    // 配置温度最小属性
    temp_min.key = "TempMin";
    temp_min.value = &stat->temp_min;
    temp_min.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    temp_min.nxt = &temp_avg;
    
    // 配置温度平均属性 (字符串类型)
    temp_avg.key = "TempAvg";
    temp_avg.value = &temp_avg1;
    temp_avg.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    temp_avg.nxt = &hum_max;  // 指向湿度属性
    
    // 配置湿度最大属性
    hum_max.key = "HumMax";
    hum_max.value = &stat->hum_max;
    hum_max.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    hum_max.nxt = &hum_min;
    
    // 配置湿度最小属性
    hum_min.key = "HumMin";
    hum_min.value = &stat->hum_min;
    hum_min.type = EN_OC_MQTT_PROFILE_VALUE_INT;
    hum_min.nxt = &hum_avg;
    
    // 配置湿度平均属性 (字符串类型)
    hum_avg.key = "HumAvg";
    hum_avg.value = &hum_avg1;
    hum_avg.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
    hum_avg.nxt = NULL;  // 最后一个属性
    
    // 配置服务
    service.event_time = NULL;
    service.service_id = "DHT11_Stat";  // 统计服务ID
    service.service_property = &temp_max;  // 指向第一个属性
    service.nxt = NULL;
    
    // 打印调试信息
    printf("TempAvg:%s,HumAvg:%s,TempMin:%d,HumMin:%d", 
           temp_avg1, hum_avg1, stat->temp_min, stat->hum_min);
    
    // 上报统计数据到华为云IoT平台
    oc_mqtt_profile_propertyreport(USERNAME, &service);
}

/**
 * @brief MQTT命令回调函数
 * @param recv_data 接收到的数据指针
 * @param recv_size 接收数据大小
 * @param resp_data 响应数据指针 (输出)
 * @param resp_size 响应数据大小 (输出)
 */
void oc_cmd_rsp_cb(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size)
{
    app_msg_t *app_msg;

    // 分配消息内存
    app_msg = malloc(sizeof(app_msg_t));
    app_msg->msg_type = en_msg_cmd;  // 设置消息类型为命令
    app_msg->msg.cmd.payload = (char *)recv_data;  // 保存接收数据

    // 打印接收到的命令
    printf("recv data is %.*s\n", recv_size, recv_data);
    
    // 将消息放入队列
    int ret = osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U);
    if (ret != 0)  // 如果入队失败
    {
        free(recv_data);  // 释放接收数据内存
    }
    
    // 不直接响应 (将在任务中处理)
    *resp_data = NULL;
    *resp_size = 0;
}

#include <cJSON.h>  // JSON解析库

/**
 * @brief 处理命令消息
 * @param cmd 命令结构指针
 */
static void deal_cmd_msg(cmd_t *cmd)
{
    cJSON *obj_root;     // JSON根对象
    cJSON *obj_cmdname;  // 命令名对象

    int cmdret = 1;  // 命令处理结果 (默认失败)
    oc_mqtt_profile_cmdresp_t cmdresp;  // 命令响应结构
    
    // 解析JSON字符串
    obj_root = cJSON_Parse(cmd->payload);
    if (NULL == obj_root)
    {
        printf("JSON parse failed\n");
        goto EXIT_JSONPARSE;  // 跳转到清理
    }

    // 获取命令名
    obj_cmdname = cJSON_GetObjectItem(obj_root, "command_name");
    if (NULL == obj_cmdname)
    {
        printf("Command name missing\n");
        goto EXIT_CMDOBJ;  // 跳转到清理
    }

    // 检查是否为重置统计命令
    if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Reset_Statistics"))
    {
        printf("Received reset statistics command\n");
        stat_init();  // 重置统计数据
        printf("Statistics reset complete\n");
        cmdret = 0;  // 设置处理成功
    }
    else
    {
        printf("Unknown command: %s\n", cJSON_GetStringValue(obj_cmdname));
    }

EXIT_CMDOBJ:
    cJSON_Delete(obj_root);  // 释放JSON对象
EXIT_JSONPARSE:
    // 配置命令响应
    cmdresp.request_id = cmd->request_id;  // 设置请求ID
    cmdresp.ret_code = cmdret;             // 设置返回码
    
    // 根据结果设置返回名称
    if (cmdret == 0) {
        cmdresp.ret_name = "SUCCESS";
    } else {
        cmdresp.ret_name = "FAILED";
    }
    
    cmdresp.paras = NULL;  // 无额外参数
    
    // 发送命令响应
    (void)oc_mqtt_profile_cmdresp(NULL, &cmdresp);
    return;
}

/**
 * @brief 主任务入口函数
 * @return 任务退出状态
 */
static int task_main_entry(void)
{
    // 连接WiFi
    uint32_t ret = WifiConnect(CONFIG_WIFI_SSID, CONFIG_WIFI_PWD);
    if (ret != 0) {
        printf("WiFi connect failed!\n");
        return -1;
    }

    // 初始化设备信息并连接华为云
    device_info_init(CLIENT_ID, USERNAME, PASSWORD);
    oc_mqtt_init();                // 初始化MQTT
    oc_set_cmd_rsp_cb(oc_cmd_rsp_cb);  // 设置命令回调

    app_msg_t *app_msg;  // 消息指针

    // 主任务循环
    while (1)
    {
        usleep(500000);  // 等待500ms
        
        // 从消息队列获取消息
        app_msg = NULL;
        (void)osMessageQueueGet(mid_MsgQueue, (void **)&app_msg, NULL, 0U);
        
        if (NULL != app_msg)
        {
            // 根据消息类型处理
            switch (app_msg->msg_type)
            {
            case en_msg_cmd:  // 命令消息
                deal_cmd_msg(&app_msg->msg.cmd);
                break;
            case en_msg_report:  // 实时数据
                deal_report_msg(&app_msg->msg.report);
                break;
            case en_msg_stat_report:  // 统计数据
                deal_stat_report(&app_msg->msg.stat_data);
                break;
            default:
                break;
            }
            free(app_msg);  // 释放消息内存
        }
    }
    return 0;
}

/**
 * @brief 传感器任务入口函数
 * @return 任务退出状态
 */
static int task_sensor_entry(void)
{
    app_msg_t *app_msg;  // 消息指针
    stat_init();         // 初始化统计
    
    int stat_counter = 0;  // 统计计数器 (每10次上报一次统计)

    // 传感器任务循环
    while (1)
    {
        sleep(3);  // 每3秒采样一次
        
        // 读取传感器数据
        int temp = DHT11_TempInt();
        int humi = DHT11_HumiInt();
        
        // 更新统计数据
        stat_update(temp, humi);
        stat_counter++;  // 增加计数
        
        // 打印传感器数据
        printf("SENSOR:temp:%d hum:%d\r\n", temp, humi);
        
        // 创建实时上报消息
        app_msg = malloc(sizeof(app_msg_t));
        if (NULL != app_msg)
        {
            app_msg->msg_type = en_msg_report;  // 设置消息类型
            app_msg->msg.report.hum = humi;     // 设置湿度值
            app_msg->msg.report.temp = temp;    // 设置温度值
            
            // 放入消息队列
            if (0 != osMessageQueuePut(mid_MsgQueue, &app_msg, 0U, 0U))
            {
                free(app_msg);  // 入队失败则释放内存
            }
        }
        
        // 每10次采样(约30秒)上报一次统计数据
        if (stat_counter % 10 == 0) 
        {
            // 创建统计上报消息
            app_msg_t *stat_msg = malloc(sizeof(app_msg_t));
            if (stat_msg != NULL) 
            {
                stat_msg->msg_type = en_msg_stat_report;  // 统计消息类型
                stat_msg->msg.stat_data = stat_get();     // 获取当前统计快照
                
                // 防止计数器溢出
                if(stat_counter > 100) {
                    stat_init();        // 重置统计
                    stat_counter = 0;   // 重置计数器
                }
                
                // 放入消息队列
                if (osMessageQueuePut(mid_MsgQueue, &stat_msg, 0U, 0U) != osOK) 
                {
                    free(stat_msg);  // 入队失败则释放
                }
            }
        }
    }
    return 0;
}

/**
 * @brief OpenHarmony 应用初始化函数
 */
static void OC_Demo(void)
{
    // 创建消息队列
    mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, sizeof(app_msg_t *), NULL);
    if (mid_MsgQueue == NULL)
    {
        printf("Failed to create Message Queue!\n");
    }

    // 配置主任务属性
    osThreadAttr_t attr = {
        .name = "task_main_entry",  // 任务名称
        .stack_size = 10240,        // 栈大小
        .priority = 24              // 优先级
    };

    // 创建主任务
    if (osThreadNew((osThreadFunc_t)task_main_entry, NULL, &attr) == NULL)
    {
        printf("Failed to create task_main_entry!\n");
    }
    
    // 配置传感器任务属性
    attr.name = "task_sensor_entry";
    attr.stack_size = 2048;  // 较小栈空间
    attr.priority = 24;      // 相同优先级
    
    // 创建传感器任务
    if (osThreadNew((osThreadFunc_t)task_sensor_entry, NULL, &attr) == NULL)
    {
        printf("Failed to create task_sensor_entry!\n");
    }
}

// OpenHarmony 特性初始化 (入口点)
APP_FEATURE_INIT(OC_Demo);